package com.qys.livesMall.app.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpUtil;
import cn.hutool.jwt.JWT;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.qys.livesMall.app.user.constants.AppUserConstant;
import com.qys.livesMall.app.user.constants.RedisConstant;
import com.qys.livesMall.app.user.enums.SmsEnum;
import com.qys.livesMall.app.user.event.LoginEvent;
import com.qys.livesMall.app.user.event.UserShopStatisticsEvent;
import com.qys.livesMall.app.user.event.UserTeamEvent;
import com.qys.livesMall.app.user.mapper.H2AppUserMapper;
import com.qys.livesMall.app.user.mapper.H2AppUserRechargeWithdrawalsMapper;
import com.qys.livesMall.app.user.model.dto.app.*;
import com.qys.livesMall.app.user.model.dto.sys.*;
import com.qys.livesMall.app.user.model.entity.*;
import com.qys.livesMall.app.user.model.enums.UserTypeEnum;
import com.qys.livesMall.app.user.model.vo.TelephoneAreaCodeVO;
import com.qys.livesMall.app.user.model.vo.app.AppUserInfoTeamDetailVo;
import com.qys.livesMall.app.user.model.vo.app.AppUserInfoVo;
import com.qys.livesMall.app.user.model.vo.app.AppUserInviteVO;
import com.qys.livesMall.app.user.model.vo.sys.*;
import com.qys.livesMall.app.user.service.*;
import com.qys.livesMall.app.user.utils.PasswordUtil;
import com.qys.livesMall.app.user.utils.SmsUtil;
import com.qys.livesMall.app.user.utils.TencentCloudIm;
import com.qys.livesMall.cache.RedisCache;
import com.qys.livesMall.cache.utils.CacheUtil;
import com.qys.livesMall.common.constants.Constants;
import com.qys.livesMall.common.constants.SysConstants;
import com.qys.livesMall.common.enums.LanguageEnum;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.thread.holder.po.LoginUser;
import com.qys.livesMall.common.utils.MessageUtils;
import com.qys.livesMall.common.utils.ip.IpUtil;
import com.qys.livesMall.common.utils.uuid.IdUtils;
import com.qys.livesMall.finance.enums.AccountBusinessTypeEnum;
import com.qys.livesMall.finance.model.dto.FinancePayDTO;
import com.qys.livesMall.finance.model.dto.user.AddUserAccount;
import com.qys.livesMall.finance.model.entity.user.FinanceUserAccount;
import com.qys.livesMall.finance.service.FinanceBusinessService;
import com.qys.livesMall.finance.service.FinanceUserAccountService;
import com.qys.livesMall.finance.util.BusinessNoUtil;
import com.qys.livesMall.framework.utils.SecurityUtils;
import com.qys.livesMall.framework.view.BaseQuery;
import com.qys.livesMall.open.mail.AsyncMailClient;
import com.qys.livesMall.open.mail.modal.MailM;
import com.qys.livesMall.system.service.BankService;
import com.qys.livesMall.system.service.SysLanguageTextService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.URLDecoder;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.qys.livesMall.common.exception.enums.ExceptionEnum.NO_SET_PWD;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author dp
 * @since 2023-04-20
 */
@Service
@Slf4j
public class H2AppUserServiceImpl extends ServiceImpl<H2AppUserMapper, H2AppUser> implements IH2AppUserService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private FinanceBusinessService financeBusinessService;

    @Autowired
    private FinanceUserAccountService financeUserAccountService;

    @Autowired
    private IH2AppUserAddressService appUserAddressService;
    @Autowired
    private IH2AppUserBankService appUserBankService;
    @Autowired
    private AppUserConcernService userConcernService;
    @Autowired
    private AppUserFriendService userFriendService;
    @Autowired
    private AppUserLevelService userLevelService;
    @Autowired
    private SysInviteRewardsService inviteRewardsService;
    @Autowired
    private AppUserGoldAccountService appUserGoldAccountService;
    @Autowired
    private BankService bankService;
    @Resource
    private TencentCloudIm tencentCloudIm;
    @Resource
    private H2AppUserRechargeWithdrawalsMapper h2AppUserRechargeWithdrawalsMapper;

    @Autowired
    private AppUserRelationService relationService;
    @Resource
    private  ApplicationContext applicationContext;
    @Resource
    private UserRewardHistoryService userRewardHistoryService;
    @Resource
    private UserRewardConfigService userRewardConfigService;
    @Resource
    private SysLanguageTextService languageTextService;

    @Resource
    private AsyncMailClient asyncMailClient;
    /**
     * 谷歌登录相关配置
     */
    @Value("${google.login.clientId}")
    private String clientId;
    @Value("${google.login.clientSecret}")
    private String clientSecret;
    @Value("${google.login.redirectUri}")
    private String redirectUri;
    @Value("${google.login.tokenUrl}")
    private String tokenUrl;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(AppUserRegisterDTO userRegisterDTO, String ip) {

        log.info("app用户注册,注册信息为: {}", userRegisterDTO);

        Pattern pattern = Pattern.compile("^[a-zA-Z0-9_@.]{6,40}$");
        Matcher matcher = pattern.matcher(userRegisterDTO.getUsername());
        if(!matcher.matches()){
            throw new QysException(MessageUtils.message("user.name.rule"));
        }

        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>()
                .eq(H2AppUser::getUserName, userRegisterDTO.getUsername());
        List<H2AppUser> appUsers = baseMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(appUsers)) {
            throw new QysException(MessageUtils.message("account.exist"));
        }

        H2AppUser h2AppUser = new H2AppUser();
        h2AppUser.setAvatar(userRegisterDTO.getAvatar());
        h2AppUser.setEmail(userRegisterDTO.getEmail());
        h2AppUser.setCreateTime(LocalDateTime.now());
        h2AppUser.setUserName(userRegisterDTO.getUsername());
        h2AppUser.setNickName(userRegisterDTO.getUsername());
        h2AppUser.setUserType(UserTypeEnum.REGULAR_USERS.getCode());
        h2AppUser.setUserSysType(AppUserConstant.SysUserType.NORMAL);
        h2AppUser.setStatus(0);
        h2AppUser.setDeleted(false);
        h2AppUser.setGoogleAccount(userRegisterDTO.getGoogleAccount());
        h2AppUser.setFacebookAccount(userRegisterDTO.getFacebookAccount());
        h2AppUser.setMobile(userRegisterDTO.getPhone());

        //生成密码信息
        generatePasswordAndSalt(userRegisterDTO.getPassword(), userRegisterDTO.getUsername(), h2AppUser);

        //上级信息
        H2AppUser parent = superiorInfo(h2AppUser, userRegisterDTO.getInviteCode());

        //生成邀请码
        h2AppUser.setInvitationCode(produceInviteCode());

        //用户显示Id（用户账号）
        h2AppUser.setUserRandomId(getRandomId());

        //用户等级
        setUserLevel(h2AppUser);

        baseMapper.insert(h2AppUser);

        //用户关系
        relationService.init(Long.valueOf(h2AppUser.getId()),h2AppUser.getSuperior());

        //用户余额表
        //userBalanceService.insertUserBalance(h2AppUser.getId(), h2AppUser.getNickName());
        financeUserAccountService.create(Long.valueOf(h2AppUser.getId()));

        //        app用户导入到IM
        tencentCloudIm.accountImport(h2AppUser.getId(), userRegisterDTO.getUsername(), h2AppUser.getAvatar());

        //邀请奖励
        this.registerReward(Long.valueOf(h2AppUser.getId()));

        UserStatisticsInfoDTO userStatisticsInfoDTO=new UserStatisticsInfoDTO();
        userStatisticsInfoDTO.setUserId(Long.valueOf(h2AppUser.getId()));
        userStatisticsInfoDTO.setUserAccount(h2AppUser.getUserName());
        userStatisticsInfoDTO.setSuperior(parent.getUserName());
        userStatisticsInfoDTO.setRegisterTime(h2AppUser.getCreateTime());
        userStatisticsInfoDTO.setRegisterIp(ip);
        userStatisticsInfoDTO.setVirtualUsers(h2AppUser.getUserSysType().toString());
        userStatisticsInfoDTO.setLockState(0);
        userStatisticsInfoDTO.setState(h2AppUser.getStatus().toString());
        userStatisticsInfoDTO.setInviteCode(h2AppUser.getInvitationCode());
        applicationContext.publishEvent(new UserShopStatisticsEvent(userStatisticsInfoDTO));
    }


    /**
     * 邀请奖励
     * @param userid 用户
     */
    private void registerReward(Long userid) {
        List<UserRewardConfig> userRewardConfigs = userRewardConfigService.list();
        if (CollectionUtils.isEmpty(userRewardConfigs)){
            return;
        }
        List<UserRewardConfig> awardUnits = userRewardConfigs.stream().filter(a->a.getAwardType()==2).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(awardUnits)){
            return;
        }
        this.transferAccounts(userid,AccountBusinessTypeEnum.USER_REGISTER_REWARD, awardUnits.get(0).getAwardUnit(),awardUnits.get(0).getConId());
    }

    @Override
    public boolean checkUserNameExist(String userName) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>()
                .eq(H2AppUser::getUserName, userName);
        List<H2AppUser> appUsers = baseMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(appUsers)) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void adds(List<H2AppUser> users, String ip) {
        this.saveBatch(users);
        List<AddUserAccount> accounts=new ArrayList<>();
        users.stream().forEach(user -> {
            relationService.init(Long.valueOf(user.getId()),user.getSuperior());
            accounts.add(new AddUserAccount(Long.valueOf(user.getId())));
        });
        financeUserAccountService.createBatch(accounts);
        appUserGoldAccountService.addAccounts(users);

        for (H2AppUser h2AppUser : users) {
            UserStatisticsInfoDTO userStatisticsInfoDTO=new UserStatisticsInfoDTO();
            userStatisticsInfoDTO.setUserId(Long.valueOf(h2AppUser.getId()));
            userStatisticsInfoDTO.setUserAccount(h2AppUser.getUserName());
            userStatisticsInfoDTO.setSuperior(h2AppUser.getSuperiorUsername());
            userStatisticsInfoDTO.setRegisterTime(h2AppUser.getCreateTime());
            userStatisticsInfoDTO.setRegisterIp(ip);
            userStatisticsInfoDTO.setVirtualUsers(h2AppUser.getUserSysType().toString());
            userStatisticsInfoDTO.setLockState(0);
            userStatisticsInfoDTO.setState(h2AppUser.getStatus().toString());
            userStatisticsInfoDTO.setInviteCode(h2AppUser.getInvitationCode());
            applicationContext.publishEvent(new UserShopStatisticsEvent(userStatisticsInfoDTO));
        }

    }

    /**
     * 生成用户明码信息
     *
     * @param h2AppUser
     * @param password
     * @param userName
     */
    private static void generatePasswordAndSalt(String password, String userName, H2AppUser h2AppUser) {
        String salt = RandomStringUtils.randomAlphanumeric(8);
        String encrypt = PasswordUtil.encrypt(password, userName, salt);
        h2AppUser.setPassword(encrypt);
        h2AppUser.setSalt(salt);
    }

    /**
     * 根据邀请码查询上级信息
     *
     * @param h2AppUser
     * @param inviteCode
     */
    private H2AppUser superiorInfo(H2AppUser h2AppUser, String inviteCode) {
        LambdaQueryWrapper<H2AppUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(H2AppUser::getInvitationCode, inviteCode);
        List<H2AppUser> appUsers = baseMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(appUsers) || appUsers.size() > 1) {
            throw new QysException(MessageUtils.message("invite.code.null"));
        }

        h2AppUser.setSuperior(Long.parseLong(appUsers.get(0).getId()));
        h2AppUser.setSuperiorName(appUsers.get(0).getNickName());
        h2AppUser.setSuperiorUsername(appUsers.get(0).getUserName());
        return appUsers.get(0);
    }

    /**
     * 生产5位数字随机邀请码
     */
    private String produceInviteCode() {
        LambdaQueryWrapper<H2AppUser> wrapper = Wrappers.lambdaQuery();

        while (true) {
            String inviteCode = RandomStringUtils.randomAlphabetic(5).toUpperCase();

            wrapper.eq(H2AppUser::getInvitationCode, inviteCode);
            List<H2AppUser> appUsers = baseMapper.selectList(wrapper);

            if (CollectionUtils.isEmpty(appUsers)) {
                return inviteCode;
            }
        }
    }

    /**
     * 用户显示Id（用户账号）
     */
    @Override
    public String getRandomId() {
        LambdaQueryWrapper<H2AppUser> wrapper = Wrappers.lambdaQuery();

        while (true) {
            String userRandomId = RandomStringUtils.randomNumeric(8);

            wrapper.eq(H2AppUser::getUserRandomId, userRandomId);
            List<H2AppUser> appUsers = baseMapper.selectList(wrapper);

            if (CollectionUtils.isEmpty(appUsers)) {
                return userRandomId;
            }
        }
    }
/*    @Override
    public String getRandomId() {
        LambdaQueryWrapper<H2AppUser> wrapper = Wrappers.lambdaQuery();
        Long userRandomId =234567L;
        wrapper.eq(H2AppUser::getUserRandomId, String.valueOf(userRandomId));
        List<H2AppUser> appUsers = baseMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(appUsers)) {
            return String.valueOf(userRandomId);
        }else {
            H2AppUser h2AppUser=baseMapper.getFinalAppUser();
            return String.valueOf(Math.addExact(Long.valueOf(h2AppUser.getUserRandomId()),17L));
        }

    }*/

    /**
     * 用户邀请奖励
     *
     * @param userid 充值用户
     */
    @Override
    public void InvitationRewards(Long userid) {
        H2AppUser h2AppUser = baseMapper.selectById(userid);
        //已邀请人数
        if (null !=  h2AppUser.getSuperior()){
            List<H2AppUser> appUsers = baseMapper.selectList(Wrappers.<H2AppUser>query()
                    .eq("superior", h2AppUser.getSuperior())
                    .eq("deleted", 0));
            if (CollectionUtils.isNotEmpty(appUsers)) {
                List<Long> userids=appUsers.stream().map(a->Long.parseLong(a.getId())).collect(Collectors.toList());
                //获取配置
                List<SysInviteRewards> inviteRewards = inviteRewardsService.list();
                if (CollectionUtils.isEmpty(inviteRewards)) {
                    log.error("未获取到平台设置邀请人数设置,不能够获得奖励信息");
                    return;
                }
                //获取邀请奖励值
                SysInviteRewards rewards = this.fetchIntervalValue(inviteRewards, userids,h2AppUser.getSuperior());
                if (null != rewards){
                    this.transferAccounts(h2AppUser.getSuperior(),AccountBusinessTypeEnum.INVITE_REWARDS, BigDecimal.valueOf(rewards.getRewards()),rewards.getId());
                }
            }else {
                log.info("用户没有直属用户，没有有效用户邀请奖励：{}", h2AppUser.getSuperior());
            }
        }
        //上级升级
        try {
            userLevelService.adjustUserLevel(userid);
           // log.info("adjustUserLevel end:{}", ok);
        } catch (Exception e) {
            log.info("adjustUserLevel error:{}",e.getMessage());
        }
    }

    /**
     * 转账
     * @param userid
     * @param accountBusinessTypeEnum
     * @param rewards
     * @param id
     * @return
     */
    @Override
    public Boolean transferAccounts(Long userid, AccountBusinessTypeEnum accountBusinessTypeEnum, BigDecimal rewards, Long id){
        FinancePayDTO payDTO = new FinancePayDTO();
        payDTO.setUserId(userid);
        payDTO.setBusinessNo(BusinessNoUtil.get(accountBusinessTypeEnum));
        payDTO.setAmountIncurred(rewards);
        payDTO.setBusinessType(accountBusinessTypeEnum);
        financeBusinessService.pay(payDTO);
        if (!payDTO.getSuccess()){
            throw new QysException(payDTO.getMessage());
        }
        //保存邀请奖励记录
        UserRewardHistory userRewardHistory=new UserRewardHistory();
        userRewardHistory.setUserId(userid);
        userRewardHistory.setType(accountBusinessTypeEnum.getType());
        userRewardHistory.setMoney(rewards);
        userRewardHistory.setCorrespondingId(id);
        userRewardHistoryService.save(userRewardHistory);
        return true;
    }

    @Override
    public void activeUser(Long userId) {
        baseMapper.activeUser(userId);
    }

    @Override
    public List<H2AppUser> getUserOtherInfoByIds(List<String> userIds) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>();
        wrapper.select(H2AppUser::getId,H2AppUser::getUserRandomId,H2AppUser::getUserName,H2AppUser::getNickName,H2AppUser::getSuperiorName);
        wrapper.in(H2AppUser::getId, userIds);
        return list(wrapper);
    }

    @Override
    public void userBindingPhone(AppUserRegisterPhoneDTO dto) {
        H2AppUser appUser=baseMapper.selectOne(Wrappers.<H2AppUser>lambdaQuery().eq(H2AppUser::getMobile, dto.getPhone()));
        if (appUser!=null){
            throw new QysException(MessageUtils.message("phone.has.bound"));
        }
        if (!dto.getPhone().startsWith("86") && !dto.getPhone().startsWith("+86") && !Objects.equals("666665", dto.getSmsCode())) {
            //   短信验证码校验
            String code = redisCache.getCacheObject(RedisConstant.SMS + dto.getPhone());
            if (StringUtils.isEmpty(code)) {
                throw new QysException("The SMS verification code is incorrect");
            } else {
                if (!dto.getSmsCode().equals(code.split(":")[0])) {
                    throw new QysException("The SMS verification code is invalid");
                }
            }
        }
        H2AppUser user=getbyUserName(dto.getUsername());
        user.setMobile(dto.getPhone());
        updateById(user);
    }

    @Override
    public void userBindingMail(AppUserRegisterMailDTO dto) {
        List<H2AppUser> h2AppUsers=baseMapper.getMail(dto.getEmail());
        if (CollectionUtils.isNotEmpty(h2AppUsers)){
            throw new QysException(MessageUtils.message("user.email.not.only"));
        }
        if (!"666665".equals(dto.getEmailCode())){
           String emailCode= redisCache.getCacheObject(RedisConstant.MAILUSERREGISTER + dto.getEmail());
           if (null == emailCode || !emailCode.split(":")[0].equals(dto.getEmailCode())){
               throw new QysException(MessageUtils.message("shop.mail.error"));
           }
        }
        H2AppUser user=getbyUserName(dto.getUsername());
        user.setEmail(dto.getEmail());
        updateById(user);
    }

    @Override
    public boolean sendMail(String mailNumber, String mailuserregister) {
        //时间
        long now = Instant.now().getEpochSecond();

        //请求是否超过一分钟
        String code = redisCache.getCacheObject(mailuserregister + mailNumber);
        if(StringUtils.isNotEmpty(code)){
            long time = Long.parseLong(code.split(":")[1]);
            if(now < time + 60){
                return false;
            }
        }

        // 生成一个六位的随机整数
        int min = 100000; // 最小值为100000（六位数的最小值）
        int max = 999999; // 最大值为999999（六位数的最大值）
        int randomNumber = new Random().nextInt(max - min + 1) + min;

        String msg=languageTextService.getByLangAndTypeId("email_code_temp", LanguageEnum.EN_US.getLang());
        if (StringUtils.isNotBlank(msg)){
            HashMap params =new HashMap();
            params.put("code",randomNumber);
            ExpressionParser parser = new SpelExpressionParser();
            TemplateParserContext parserContext = new TemplateParserContext();
            msg = parser.parseExpression(msg,parserContext).getValue(params, String.class);
        }
        if (msg==null) {
            msg=MessageUtils.message("sms.template");
            msg = String.format(msg, randomNumber);
            //发送短信
        }

        MailM m=new MailM();
        m.setTitle(MessageUtils.message("shop.mail.title"));
        m.setMsg(msg);
        m.setToUsers(Arrays.asList(mailNumber));

        asyncMailClient.send(m);
        redisCache.setCacheObject(mailuserregister + mailNumber, randomNumber + ":" + now, 15L, TimeUnit.MINUTES);
        return true;
    }

    @Override
    public List<H2AppUser> getWeek() {
        return baseMapper.getgetWeek();
    }

    @Override
    public H2AppUser getUserByRandomId(String superior) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>();
        wrapper.eq(H2AppUser::getUserRandomId,superior);
        return baseMapper.selectOne(wrapper);
    }

    private Integer getConfigurationMaximum(List<SysInviteRewards> inviteRewards){
        List<SysInviteRewards> collect = inviteRewards.stream().sorted(Comparator.comparing(SysInviteRewards::getMaxNum).reversed()).toList();
        return collect.get(0).getMaxNum();
    }

    private SysInviteRewards fetchIntervalValue(List<SysInviteRewards> inviteRewards, List<Long> userids,Long userid){
        for (SysInviteRewards sysInviteRewards:inviteRewards) {
           Integer result = h2AppUserRechargeWithdrawalsMapper.getSatisfyRechargeNmu(userids,sysInviteRewards.getRechargeAsk());
           if (sysInviteRewards.getMinNum() <= result && sysInviteRewards.getMaxNum() > result){
               //查询是否奖励过
               List<UserRewardHistory> list=userRewardHistoryService.getUserRewardHistory(userid,AccountBusinessTypeEnum.INVITE_REWARDS.getType(),sysInviteRewards.getId());
               if (CollectionUtils.isEmpty(list)){
                   //返回对应奖励
                   return sysInviteRewards;
               }
           }
        }
        return null;
    }

    /**
     * 用户设置默认等级信息
     *
     * @param h2AppUser
     */
    private void setUserLevel(H2AppUser h2AppUser) {
        AppUserLevel level = userLevelService.getOne(Wrappers.<AppUserLevel>query().orderByAsc("level").last("LIMIT 1"));
        if (null == level) {
            return;
        }

        h2AppUser.setUserLevel(level.getName());
        h2AppUser.setUserLevelId(Long.valueOf(level.getId()));
    }

    @Override
    public String login(AppLoginDTO appLoginDTO, HttpServletRequest request) {
        log.info("app用户登录，登录信息: {}", appLoginDTO);

        H2AppUser appUser = baseMapper.selectOne(Wrappers.<H2AppUser>lambdaQuery().eq(H2AppUser::getUserName, appLoginDTO.getUsername()));
        //账号不存在
        if (null == appUser) {
            //手机号
            appUser = baseMapper.selectOne(Wrappers.<H2AppUser>lambdaQuery().like(H2AppUser::getMobile, appLoginDTO.getUsername()).last("limit 1"));
            if (null == appUser || !appUser.getMobile().equals(appLoginDTO.getUsername())) {
                throw new QysException(MessageUtils.message("user.register"));
            }
            appLoginDTO.setUsername(appUser.getUserName());
        }
        //账号被冻结
        if (appUser.getStatus() == 1) {
            throw new QysException(MessageUtils.message("user.blocked"));
        }
        //密码校验
        String userpassword = PasswordUtil.encrypt(appLoginDTO.getPassword(), appLoginDTO.getUsername(), appUser.getSalt());
        if (!Objects.equals(userpassword, appUser.getPassword())) {
            throw new QysException(MessageUtils.message("usernameOrPassword.error"));
        }

        return this.doLogin(request,appUser);

    }

    /**
     * 检查是否导入用户到IM
     * @param appUser
     */
    private void checkImImport(H2AppUser appUser) {
        try {
            //        查询用户是否导入到IM
            List<String> userIds = new ArrayList<>();
            userIds.add(appUser.getId());
            Map<String, Boolean> resultMap = tencentCloudIm.accountCheck(userIds);
            Boolean flag = resultMap.get(appUser.getId());
//        如果没有导入IM  则重新导入
            if (!flag) {
                tencentCloudIm.accountImport(appUser.getId(), appUser.getNickName(), appUser.getAvatar());
            }
        } catch (Exception e) {
            log.error("检查用户导入IM异常 message:[{}]",e.getMessage());
        }
    }


    @Override
    public void loginOut(String token) {
        String key = CacheUtil.getKey(RedisConstant.USER_TOKEN, token);
        LoginUser loginUser = redisCache.getCacheObject(key);

        if (null != loginUser) {
            redisCache.deleteObject(key);

            key = CacheUtil.getKey(RedisConstant.USER_ID_TOKEN, String.valueOf(loginUser.getUserId()));
            redisCache.deleteObject(key);
        }
    }

    @Override
    public Page<SysAppUserPageVo> pageSys(SysAppUserQueryDTO userQueryDTO) {
        Page<SysAppUserPageVo> page = new Page<>(userQueryDTO.getPageNum(), userQueryDTO.getPageSize());
        List<SysAppUserPageVo> pageVoList = baseMapper.pageSys(page, userQueryDTO);

        if (CollectionUtils.isNotEmpty(pageVoList)) {
            List<SysAppUserPageVo> voList = new ArrayList<>();
            pageVoList.forEach(vo -> {
                //余额信息
                FinanceUserAccount userBalance = financeUserAccountService.get(vo.getId());
                if (null != userBalance) {
                    vo.setAmount(userBalance.getTotalBalance());
                }

                //下级数量
                vo.setLowerCount(baseMapper.countBySuperior(String.valueOf(vo.getId())));

                //订单数量 TODO

                //判断水军是否被占用
                vo.setNavyStatus(this.getNavyStatus(vo.getId()));
                voList.add(vo);
            });
            page.setRecords(voList);
        }
        return page;
    }

    /**
     * 判断水军是否被占用
     * @return 1已占用，0未占用
     */
    private Integer getNavyStatus(Long id) {
        List<String> task = baseMapper.exampleQueryATaskInProgress();
        for (String one : task) {
            JSONObject jsonObject = JSONObject.parseObject(one);
            JSONArray navyIds = jsonObject.getJSONArray("navyIds");
            List<Long> idsList = navyIds.toJavaList(Long.class);
            if(idsList.contains(id)){
                return 1;
            }
        }
        return 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysAppUserSaveDTO sysAppUserSaveDTO,String ip) {
        log.info("管理员添加用户信息:{}", sysAppUserSaveDTO);

        H2AppUser user = new H2AppUser();
        BeanUtils.copyProperties(sysAppUserSaveDTO, user);
        user.setUpdateBy(SecurityUtils.getUsername());
        user.setUpdateTime(LocalDateTime.now());

        //新增
        if (StringUtils.isBlank(sysAppUserSaveDTO.getId())) {
            user.setUserSysType(AppUserConstant.SysUserType.NORMAL);
            user.setStatus(0);
            user.setDeleted(false);
            user.setUserType(UserTypeEnum.REGULAR_USERS.getCode());
            user.setNickName(sysAppUserSaveDTO.getUserName());
            user.setCreateTime(LocalDateTime.now());
            user.setCreateBy(SecurityUtils.getUsername());

            //上级信息 默认总店
            superiorInfo(user, "ASDFG");

            //生成邀请码
            user.setInvitationCode(produceInviteCode());

            //用户显示Id（用户账号）
            user.setUserRandomId(getRandomId());

            //用户等级
            setUserLevel(user);
        }

        //生成密码信息
        generatePasswordAndSalt(sysAppUserSaveDTO.getPassword(), sysAppUserSaveDTO.getUserName(), user);

        saveOrUpdate(user);

        if (StringUtils.isBlank(sysAppUserSaveDTO.getId())) {
            //用户余额表
            financeUserAccountService.create(Long.valueOf(user.getId()));

            //地址信息
            if (sysAppUserSaveDTO.getCountry() != null) {
                AppUserAddressDTO appUserAddressDTO = new AppUserAddressDTO();
                BeanUtils.copyProperties(sysAppUserSaveDTO, appUserAddressDTO);
                appUserAddressDTO.setDefaultAddress(true);
                appUserAddressService.save(appUserAddressDTO, user.getId());
            }

            //银行卡信息
            appUserBankService.save(sysAppUserSaveDTO, user.getId());
            UserStatisticsInfoDTO userStatisticsInfoDTO=new UserStatisticsInfoDTO();
            userStatisticsInfoDTO.setUserId(Long.valueOf(user.getId()));
            userStatisticsInfoDTO.setUserAccount(user.getUserName());
            userStatisticsInfoDTO.setSuperior(user.getSuperiorUsername());
            userStatisticsInfoDTO.setRegisterTime(user.getCreateTime());
            userStatisticsInfoDTO.setRegisterIp(ip);
            userStatisticsInfoDTO.setVirtualUsers(user.getUserSysType().toString());
            userStatisticsInfoDTO.setLockState(0);
            userStatisticsInfoDTO.setState(user.getStatus().toString());
            userStatisticsInfoDTO.setInviteCode(user.getInvitationCode());
            applicationContext.publishEvent(new UserShopStatisticsEvent(userStatisticsInfoDTO));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(NewSysAppUserVo dto) {

        H2AppUser appUser = getById(dto.getUserId());
        if(appUser==null){
            return;
        }

        H2AppUser user = new H2AppUser();
        user.setId(String.valueOf(dto.getUserId()));
        user.setAvatar(dto.getUserAvatar());
        user.setNickName(dto.getNickName());
        if(null != dto.getPhoneNum()){
            user.setMobile(dto.getPhoneNum());
        }
        user.setUpdateBy(SecurityUtils.getUsername());
        user.setUpdateTime(LocalDateTime.now());
        List<Integer> levelIds=null;
        if(dto.getUserLevelId()!=null){
            AppUserLevel level = userLevelService.getOne(Wrappers.<AppUserLevel>lambdaQuery().eq(AppUserLevel::getLevel,dto.getUserLevelId()));
            user.setUserLevelId(dto.getUserLevelId());
            user.setUserLevel(null==level?null:level.getName());
            if (appUser.getUserLevelId() < dto.getUserLevelId()){
                LambdaQueryWrapper<AppUserLevel> queryWrapper=new LambdaQueryWrapper<>();
                queryWrapper.gt(AppUserLevel::getLevel,appUser.getUserLevelId());
                queryWrapper.le(AppUserLevel::getLevel,dto.getUserLevelId());
                List<AppUserLevel> list=userLevelService.list(queryWrapper);
                levelIds=list.stream().map(AppUserLevel::getId).toList();
            }
        }
        if(StringUtils.isNotBlank(dto.getLoginPassword())){
            user.setPassword(PasswordUtil.encrypt(dto.getLoginPassword(),dto.getUserName(),appUser.getSalt()));
        }
        if(StringUtils.isNotBlank(dto.getPayPassword())){
            user.setUserWithdrawalPassword(PasswordUtil.encrypt(dto.getPayPassword(),dto.getUserName(),appUser.getSalt()));
        }
        updateById(user);

        if (CollectionUtils.isNotEmpty(dto.getAddress())) {
            //更新
            dto.getAddress().forEach(e->{
                H2AppUserAddress appUserAddress = new H2AppUserAddress();
                appUserAddress.setId(e.getId());
                appUserAddress.setAddress(e.getAddress());
                appUserAddressService.updateById(appUserAddress);
            });
        }
        //升级奖励
        if (CollectionUtils.isNotEmpty(levelIds)){
            LambdaQueryWrapper<UserRewardConfig> wrapper=new LambdaQueryWrapper<>();
            wrapper.eq(UserRewardConfig::getAwardType,8);
            wrapper.last("limit 1");
            UserRewardConfig userRewardConfig=userRewardConfigService.getOne(wrapper);
            for (Integer levelid:levelIds) {
                LambdaQueryWrapper<UserRewardHistory> queryWrapper=new LambdaQueryWrapper<>();
                queryWrapper.eq(UserRewardHistory::getUserId,dto.getUserId());
                queryWrapper.eq(UserRewardHistory::getType, AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS.getType());
                queryWrapper.eq(UserRewardHistory::getCorrespondingId,levelid);
                List<UserRewardHistory> list=userRewardHistoryService.list(queryWrapper);
                if (CollectionUtils.isEmpty(list)){
                    FinancePayDTO payDTO = new FinancePayDTO();
                    payDTO.setUserId(dto.getUserId());
                    payDTO.setBusinessNo(BusinessNoUtil.get(AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS));
                    payDTO.setAmountIncurred(userRewardConfig.getAwardUnit().multiply(new BigDecimal(levelid)));
                    payDTO.setBusinessType(AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS);
                    financeBusinessService.pay(payDTO);
                    if (!payDTO.getSuccess()){
                        throw new QysException(payDTO.getMessage());
                    }
                    //保存升级奖励记录
                    UserRewardHistory userRewardHistory=new UserRewardHistory();
                    userRewardHistory.setUserId(dto.getUserId());
                    userRewardHistory.setType(AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS.getType());
                    userRewardHistory.setMoney(userRewardConfig.getAwardUnit().multiply(new BigDecimal(levelid)));
                    userRewardHistory.setCorrespondingId(Long.valueOf(levelid));
                    userRewardHistoryService.save(userRewardHistory);
                }
            }
        }
/*
        if(CollectionUtils.isNotEmpty(dto.getBankCard())){
            //更新
            dto.getBankCard().forEach(e->{
                UserBankCard userBankCard = new UserBankCard();
                userBankCard.setId(e.getId());
                userBankCard.setAccountName(e.getAccountName());
                userBankCard.setCardNumber(e.getCardNumber());
                userBankCard.setBankId(e.getBankId());
                userBankCardService.updateById(userBankCard);
            });
        }

        if(StringUtils.isNotBlank(dto.getPurse())){
            Wrapper<UserWallet> wrapper = Wrappers.<UserWallet>lambdaUpdate().eq(UserWallet::getUserId, dto.getUserId()).eq(UserWallet::getWalletAddress, dto.getPurse());
            UserWallet wallet = new UserWallet();
            wallet.setWalletAddress(dto.getPurse());
            userWalletService.update(wallet,wrapper);
        }*/

    }

    @Override
    public void editUser(EditSysAppUserDTO dto) {
        H2AppUser appUser = getById(dto.getUserId());
        if(appUser==null){
            return;
        }
        switch (dto.getType()){
            case 1:
                appUser.setNickName(dto.getUserValue());
                break;
            case 2:
                appUser.setPassword(PasswordUtil.encrypt(dto.getUserValue(),appUser.getUserName(),appUser.getSalt()));
                break;
            case 3:
                appUser.setUserWithdrawalPassword(PasswordUtil.encrypt(dto.getUserValue(),appUser.getUserName(),appUser.getSalt()));
                break;
            case 4:
                List<Integer> levelIds=null;
                AppUserLevel level = userLevelService.getOne(Wrappers.<AppUserLevel>lambdaQuery().eq(AppUserLevel::getLevel,Long.valueOf(dto.getUserValue())));
                appUser.setUserLevelId(Long.valueOf(dto.getUserValue()));
                appUser.setUserLevel(null==level?null:level.getName());
                if (appUser.getUserLevelId() < Long.valueOf(dto.getUserValue())){
                    LambdaQueryWrapper<AppUserLevel> queryWrapper=new LambdaQueryWrapper<>();
                    queryWrapper.gt(AppUserLevel::getLevel,appUser.getUserLevelId());
                    queryWrapper.le(AppUserLevel::getLevel,Long.valueOf(dto.getUserValue()));
                    List<AppUserLevel> list=userLevelService.list(queryWrapper);
                    levelIds=list.stream().map(AppUserLevel::getId).toList();
                }
                //升级奖励
                if (CollectionUtils.isNotEmpty(levelIds)){
                    LambdaQueryWrapper<UserRewardConfig> wrapper=new LambdaQueryWrapper<>();
                    wrapper.eq(UserRewardConfig::getAwardType,8);
                    wrapper.last("limit 1");
                    UserRewardConfig userRewardConfig=userRewardConfigService.getOne(wrapper);
                    for (Integer levelid:levelIds) {
                        LambdaQueryWrapper<UserRewardHistory> queryWrapper=new LambdaQueryWrapper<>();
                        queryWrapper.eq(UserRewardHistory::getUserId,dto.getUserId());
                        queryWrapper.eq(UserRewardHistory::getType, AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS.getType());
                        queryWrapper.eq(UserRewardHistory::getCorrespondingId,levelid);
                        List<UserRewardHistory> list=userRewardHistoryService.list(queryWrapper);
                        if (CollectionUtils.isEmpty(list)){
                            FinancePayDTO payDTO = new FinancePayDTO();
                            payDTO.setUserId(dto.getUserId());
                            payDTO.setBusinessNo(BusinessNoUtil.get(AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS));
                            payDTO.setAmountIncurred(userRewardConfig.getAwardUnit().multiply(new BigDecimal(levelid)));
                            payDTO.setBusinessType(AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS);
                            financeBusinessService.pay(payDTO);
                            if (!payDTO.getSuccess()){
                                throw new QysException(payDTO.getMessage());
                            }
                            //保存升级奖励记录
                            UserRewardHistory userRewardHistory=new UserRewardHistory();
                            userRewardHistory.setUserId(dto.getUserId());
                            userRewardHistory.setType(AccountBusinessTypeEnum.USER_LEVEL_UPGRADE_REWARDS.getType());
                            userRewardHistory.setMoney(userRewardConfig.getAwardUnit().multiply(new BigDecimal(levelid)));
                            userRewardHistory.setCorrespondingId(Long.valueOf(levelid));
                            userRewardHistoryService.save(userRewardHistory);
                        }
                    }
                }
                break;
            case 5:
                appUser.setAvatar(dto.getUserValue());
                break;
            default:
                throw new QysException("type Mismatch");
        }
        updateById(appUser);
    }

    @Override
    public NewSysAppUserVo queryById(String id) {

        //用户基本信息
        H2AppUser h2AppUser = baseMapper.selectById(id);
        if (null == h2AppUser) {
            throw new QysException(MessageUtils.message("user.null"));
        }

        //用户地址
        List<H2AppUserAddress> addresses = appUserAddressService.list(Wrappers.<H2AppUserAddress>lambdaQuery().eq(H2AppUserAddress::getUserId, id));
        List<AppUserAddressDTO> addressDTOList = addresses.stream().map(e -> {
            AppUserAddressDTO addressDTO = new AppUserAddressDTO();
            addressDTO.setId(e.getId());
            addressDTO.setAddress(e.getAddress());
            return addressDTO;
        }).toList();


/*        //用户银行卡
        List<UserBankCard> userBankCards = userBankCardService.list(Wrappers.<UserBankCard>lambdaQuery().eq(UserBankCard::getUserId, h2AppUser.getId()));
        List<UserBankCardVO> cardVOStream = userBankCards.stream().map(e -> {
            UserBankCardVO userBankCardVO = new UserBankCardVO();
            userBankCardVO.setId(e.getId());
            userBankCardVO.setCardNumber(e.getCardNumber());
            userBankCardVO.setAccountName(e.getAccountName());
            userBankCardVO.setBankId(e.getBankId());
            userBankCardVO.setBankName(bankService.getById(e.getBankId()).getBankName());
            return userBankCardVO;
        }).collect(Collectors.toList());

        //用户钱包
        UserWallet userWallet = userWalletService.getOne(Wrappers.<UserWallet>lambdaQuery().eq(UserWallet::getUserId, id));*/

        //返回数据
        NewSysAppUserVo sysAppUserVo = new NewSysAppUserVo();
       // sysAppUserVo.setBankCard(cardVOStream);
        sysAppUserVo.setUserId(Long.parseLong(h2AppUser.getId()));
        sysAppUserVo.setUserName(h2AppUser.getUserName());
        sysAppUserVo.setUserAvatar(h2AppUser.getAvatar());
        sysAppUserVo.setNickName(h2AppUser.getNickName());
//        sysAppUserVo.setLoginPassword(h2AppUser.getPassword());
//        sysAppUserVo.setPayPassword(h2AppUser.getUserWithdrawalPassword());
        sysAppUserVo.setPhoneNum(null==h2AppUser.getMobile()?null:String.valueOf(h2AppUser.getMobile()));
        sysAppUserVo.setUserLevelId(h2AppUser.getUserLevelId());
        sysAppUserVo.setUserLevelName(h2AppUser.getUserLevel());
        sysAppUserVo.setEmail(null);
     //   sysAppUserVo.setPurse(userWallet!=null?userWallet.getWalletAddress():null);
        sysAppUserVo.setAddress(addressDTOList);
        return sysAppUserVo;
    }

    @Override
    public void top(String userId, boolean top) {
        H2AppUser appUser = new H2AppUser();
        appUser.setTop(top);
        setUpdateInfo(userId, appUser);
        baseMapper.updateById(appUser);
    }

    @Override
    public void waterArmy(String userId) {
        H2AppUser h2AppUser = baseMapper.selectById(userId);
        if (null == h2AppUser) {
            throw new QysException(MessageUtils.message("user.null"));
        }

        H2AppUser appUser = new H2AppUser();
        appUser.setUserSysType(appUser.getUserSysType()==null||appUser.getUserSysType().equals(0)?AppUserConstant.SysUserType.NORMAL:AppUserConstant.SysUserType.NAVY);
        setUpdateInfo(userId, appUser);
        baseMapper.updateById(appUser);
        String key = CacheUtil.getKey(AppUserConstant.AppUserRedisKeyPrefix.USER_SYS_TYPE, String.valueOf(userId));
        redisCache.setCacheObject(key,appUser.getUserSysType(),1L,TimeUnit.DAYS);

    }

    private void setUpdateInfo(String id, H2AppUser appUser) {
        appUser.setId(id);
        appUser.setUpdateTime(LocalDateTime.now());
        appUser.setUpdateBy(appUser.getUpdateBy());
    }

    @Override
    public AppUserInfoVo queryUserIno(Long userId) {
        H2AppUser h2AppUser = baseMapper.queryUserIno(userId);
        if (null == h2AppUser) {
            throw new QysException(MessageUtils.message("user.null"));
        }
        AppUserInfoVo userInfoVo = new AppUserInfoVo();
        BeanUtils.copyProperties(h2AppUser, userInfoVo);
        userInfoVo.setNewUserRandomId(h2AppUser.getUserRandomId());
        userInfoVo.setUserRandomId(h2AppUser.getAnchorId()==null?null:h2AppUser.getAnchorId().toString());
        if (null!=h2AppUser.getUserLevelId()){
            AppUserLevel appUserLevel = userLevelService.getById(h2AppUser.getUserLevelId());
            userInfoVo.setLevel(appUserLevel.getLevel());
            userInfoVo.setUserLevelIcon(appUserLevel.getIcon());
        }
        // 用户点赞/粉丝/互关
        setUserOtherInfo(userId, userInfoVo);
        //送出的金币
        BigDecimal sumGivingGifts=baseMapper.getAnchorLivesGiftRecord(userId);
        userInfoVo.setGivingGifts(sumGivingGifts);
        //直播等级
        String liveStreamingLevel=baseMapper.getLiveStreamingLevel(userId);
        userInfoVo.setLiveStreamingLevel(liveStreamingLevel);

        H2ShopBaseVO h2ShopBaseVO=baseMapper.getShopInfo(userId);
        if (null != h2ShopBaseVO){
            userInfoVo.setShopId(h2ShopBaseVO.getId());
        }
        //商店账户
        return userInfoVo;
    }

    /**
     * 设置用户点赞/互关/粉丝信息
     *
     * @param userId
     * @param userInfoVo
     */
    private void setUserOtherInfo(Long userId, AppUserInfoVo userInfoVo) {
        QueryWrapper<AppUserConcern> wrapper = Wrappers.<AppUserConcern>query();

        //关注
        wrapper.eq("user_Id", userId).eq("status", 1);
        List<AppUserConcern> concerns = userConcernService.list(wrapper);
        userInfoVo.setConcern(concerns.size());

        //粉丝
        wrapper.clear();
        wrapper.eq("concern_id", userId).eq("status", 1);
        concerns = userConcernService.list(wrapper);
        userInfoVo.setFans(concerns.size());

        //互关
        List<AppUserFriend> friends = userFriendService.list(Wrappers.<AppUserFriend>query().eq("user_Id", userId)
                .eq("status", 1));
        userInfoVo.setInterconnection(friends.size());

        //点赞
        userInfoVo.setLike(baseMapper.countVideoLIke(userId));
    }

    @Override
    public void changePassword(PasswordDTO passwordDTO, Long userId) {
        H2AppUser h2AppUser = baseMapper.selectById(userId);
        if (null == h2AppUser) {
            throw new QysException(MessageUtils.message("user.null"));
        }

        //旧密码
        String encryptOld = PasswordUtil.encrypt(passwordDTO.getOldPassword(), h2AppUser.getUserName(), h2AppUser.getSalt());
        //新密码
        String newPwd = PasswordUtil.encrypt(passwordDTO.getPassword(), h2AppUser.getUserName(), h2AppUser.getSalt());

        H2AppUser saveUser = new H2AppUser();
        saveUser.setUpdateBy(h2AppUser.getUserName());
        setUpdateInfo(String.valueOf(userId), saveUser);

        switch (passwordDTO.getType()) {
            case 0 -> {
                //登录密码
                if (!Objects.equals(encryptOld, h2AppUser.getPassword())) {
                    throw new QysException(MessageUtils.message("password.error"));
                }
                saveUser.setPassword(newPwd);
            }
            case 1 -> {
                // 用户提现密码
                if (!Objects.equals(encryptOld, h2AppUser.getUserWithdrawalPassword())) {
                    throw new QysException(MessageUtils.message("password.error"));
                }
//                boolean ok = SmsUtil.verifyCode(SmsEnum.FORGOT_PASSWORD, passwordDTO.getPhone(), passwordDTO.getSmsCode());
//                if (!ok) {
//                    throw new QysException("The SMS verification code is invalid");
//                }
                saveUser.setUserWithdrawalPassword(newPwd);
            }
            case 2 -> {
                //店铺提现密码
                if (!Objects.equals(encryptOld, h2AppUser.getStoreWithdrawalPassword())) {
                    throw new QysException(MessageUtils.message("password.error"));
                }
                saveUser.setStoreWithdrawalPassword(newPwd);
            }
            case 3 -> {
                //主播提现密码
                if (!Objects.equals(encryptOld, h2AppUser.getAnchorWithdrawalPassword())) {
                    throw new QysException(MessageUtils.message("password.error"));
                }
                saveUser.setAnchorWithdrawalPassword(newPwd);
            }
            case 4 -> {
                if (null !=  passwordDTO.getSmsCode()) {
                    boolean ok = SmsUtil.verifyCode(SmsEnum.FORGOT_PASSWORD, passwordDTO.getPhone(), passwordDTO.getSmsCode());
                    if (!ok) {
                        throw new QysException("The SMS verification code is invalid");
                    }
                }else {
                    String emailCode= redisCache.getCacheObject(RedisConstant.MAILUSERREGISTER + passwordDTO.getEmail());
                    if (!emailCode.equals(passwordDTO.getEmailCode())){
                        throw new QysException(MessageUtils.message("shop.mail.error"));
                    }
                }
                //忘记密码
                saveUser.setPassword(newPwd);
            }
        }

        baseMapper.updateById(saveUser);
    }

    @Override
    public void setPassword(PasswordDTO passwordDTO, Long userId) {
        H2AppUser h2AppUser = baseMapper.selectById(userId);
        if (null == h2AppUser) {
            throw new QysException(MessageUtils.message("user.null"));
        }

        String newPwd = PasswordUtil.encrypt(passwordDTO.getPassword(), h2AppUser.getUserName(), h2AppUser.getSalt());
        H2AppUser saveUser = new H2AppUser();
        setUpdateInfo(String.valueOf(userId), saveUser);

        switch (passwordDTO.getType()) {
            case 1 -> {
                // 用户提现密码
                if (StringUtils.isNotBlank(h2AppUser.getUserWithdrawalPassword())) {
                    throw new QysException(MessageUtils.message("unknown.error"));
                }
                saveUser.setUserWithdrawalPassword(newPwd);
            }
            case 2 -> {
                //店铺提现密码
                if (StringUtils.isNotBlank(h2AppUser.getStoreWithdrawalPassword())) {
                    throw new QysException(MessageUtils.message("unknown.error"));
                }
                saveUser.setStoreWithdrawalPassword(newPwd);
            }
            case 3 -> {
                //主播提现密码
                if (StringUtils.isNotBlank(h2AppUser.getAnchorWithdrawalPassword())) {
                    throw new QysException(MessageUtils.message("unknown.error"));
                }
                saveUser.setAnchorWithdrawalPassword(newPwd);
            }
        }

        baseMapper.updateById(saveUser);
    }

    /**
     * 用户提现校验密码信息
     *
     * @param id
     * @param password
     */
    public boolean checkUserPayPassword(String id, String password) {
        H2AppUser appUser=getById(id);
        //未设置密码
        if (StringUtils.isBlank(appUser.getUserWithdrawalPassword())) {
            throw new QysException(MessageUtils.message("set.password"));
        }

        //密码校验
        String inputPwd = PasswordUtil.encrypt(password, appUser.getUserName(), appUser.getSalt());
        if (!Objects.equals(inputPwd, appUser.getUserWithdrawalPassword())) {
            throw new QysException(MessageUtils.message("password.error"));
        }
        return true;
    }

    /**
     * app修改用户信息
     *
     * @param editDTO
     */
    @Override
    public void save(AppUserEditDTO editDTO) {
        log.info("APP用户修改用户信息：{}", editDTO);

        H2AppUser user = new H2AppUser();
        BeanUtils.copyProperties(editDTO, user);

        if (null != editDTO.getBirthday()) {
            if(!editDTO.getBirthday().isBefore(LocalDate.now())){
                throw new QysException(MessageUtils.message("user.birthday.error"));
            }
            user.setAge(LocalDate.now().getYear() - user.getBirthday().getYear());
        }
        int success = baseMapper.updateById(user);
        if(success>0 && !StringUtils.isAllBlank(editDTO.getNickName(),editDTO.getAvatar())){
            tencentCloudIm.updateUser(user.getId(),editDTO.getAvatar(),editDTO.getNickName());
        }
    }

    /**
     * 后台管理分页查询用户信息
     *
     * @param userQueryDTO
     * @return
     */
    @Override
    public List<SysAppUserPageVo> listUserInfo(SysAppUserQueryDTO userQueryDTO) {
        return baseMapper.pageSys(null, userQueryDTO);
    }

    /**
     * 用户邀请记录查询
     *
     * @param baseQuery
     */
    @Override
    public Page<AppUserInviteVO> queryUserInviteHistory(BaseQuery baseQuery) {
        Page<AppUserInviteVO> page = new Page<>(baseQuery.getPageNum(), baseQuery.getPageSize());
        page.setRecords(baseMapper.queryUserInviteHistory(baseQuery));
        return page;
    }

    @Override
    public void becomeShopkeeper(Long userId) {
        H2AppUser user=baseMapper.selectById(userId);
        if (Objects.equals(UserTypeEnum.REGULAR_USERS.getCode(),user.getUserType())){
            user.setUserType(UserTypeEnum.STORE.getCode());
        }else if(Objects.equals(UserTypeEnum.ANCHOR.getCode(),user.getUserType())){
            user.setUserType(UserTypeEnum.STORE_AND_ANCHOR.getCode());
        }
        baseMapper.updateById(user);
    }

    @Override
    public void becomeAnchor(Long userId) {
        H2AppUser user=baseMapper.selectById(userId);
        if (Objects.equals(UserTypeEnum.REGULAR_USERS.getCode(),user.getUserType())){
            user.setUserType(UserTypeEnum.ANCHOR.getCode());
        }else if(Objects.equals(UserTypeEnum.STORE.getCode(),user.getUserType())){
            user.setUserType(UserTypeEnum.STORE_AND_ANCHOR.getCode());
        }
        baseMapper.updateById(user);
    }

    @Override
    public boolean checkPassWord(Long userId, String payPassword, int type) {
        boolean flag=true;
        H2AppUser user = getById(userId);
        if (type==1){
            String userWithdrawalPassword = user.getUserWithdrawalPassword();
            if (StringUtils.isBlank(userWithdrawalPassword)){
                throw new QysException(NO_SET_PWD);
            }else {
                String inputPwd = PasswordUtil.encrypt(payPassword, user.getUserName(), user.getSalt());
                if (!Objects.equals(inputPwd, user.getUserWithdrawalPassword())) {
                    flag=false;
                }
            }
        }

        return flag;
    }

    @Override
    public Map<String, String> loginByGoogle(String code, HttpServletRequest request) {

        Map<String, String> map = Maps.newHashMap();

        //判断传入的code是用户唯一id还是授权码（用户唯一id为纯数字）
        if(code.matches("\\d+")){
            //一.app渠道(使用用户唯一标识)
            H2AppUser appUser = baseMapper.selectOne(Wrappers.<H2AppUser>lambdaQuery().eq(H2AppUser::getGoogleAccount, code));
            if(null != appUser){
                map.put("token",this.doLogin(request,appUser));
            } else {
                map.put("uniqueId", code);
                map.put("token",StringUtils.EMPTY);
            }
        } else {
            //二.web渠道(使用code授权登录)
            Map<String, String> uniqueID = getUniqueID(code);
            H2AppUser appUser2 = baseMapper.selectOne(Wrappers.<H2AppUser>lambdaQuery().eq(H2AppUser::getGoogleAccount, uniqueID.get("sub")));
            //判断是否绑定注册账号
            if(null == appUser2){
                map.put("uniqueId",uniqueID.get("sub"));
                map.put("user",uniqueID.get("email"));
                map.put("token",StringUtils.EMPTY);
            } else {
                map.put("token",this.doLogin(request,appUser2));
            }
        }
        return map;
    }


    @Override
    public Map<String, String> facebookLogin(String userId, String userToken, HttpServletRequest request) {

        //1、校验token并获取用户昵称
        String url = String.format("https://graph.facebook.com/%s?access_token=%s", userId, userToken);
        String result = HttpUtil.get(url);

        //2、根据返回获取脸书的账号id和昵称
        JSONObject jsonObject = JSONObject.parseObject(result);
        if(jsonObject.get("name") == null){
            throw new QysException("facebookLogin error");
        }

        String fbUserName = Convert.unicodeToStr((String)jsonObject.get("name"));
        String fbUserId = (String)jsonObject.get("id");

        Map<String, String> map = Maps.newHashMap();
        //2、判断用户是否存在
        H2AppUser appUserByFB = baseMapper.selectOne(Wrappers.<H2AppUser>lambdaQuery().eq(H2AppUser::getFacebookAccount, fbUserId));
        if(null == appUserByFB){
            //判断是否绑定注册账号
            map.put("uniqueId", fbUserId);
            map.put("user", fbUserName);
            map.put("token",StringUtils.EMPTY);
        } else {
            map.put("token",this.doLogin(request, appUserByFB));
        }
        return map;
    }

    @Override
    public List<String> getsubsetList(String id) {
        return baseMapper.getsubsetList(id);
    }

    @Override
    public boolean userIsNavy(String userId) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>();
        wrapper.eq(H2AppUser::getId, userId);
        wrapper.eq(H2AppUser::getUserSysType, Constants.YesNo.NO);
        wrapper.eq(H2AppUser::getDeleted, Constants.YesNoInt.NO);
        return baseMapper.exists(wrapper);
    }

    @Override
    public Page<SysAppUserActivePageVo> activeUserPage(BaseQuery baseQuery) {
        Page<SysAppUserActivePageVo> page = new Page<>(baseQuery.getPageNum(), baseQuery.getPageSize());
        page = baseMapper.activeUserPage(page, baseQuery);
        return page;
    }

    @Override
    public List<Long> getUserIdByQuery(UserQuery query) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>();
        wrapper.select(H2AppUser::getId);
        boolean exc=false;
        if (CollectionUtils.isNotEmpty(query.getUserIds())) {
            wrapper.in(H2AppUser::getId, query.getUserIds());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getUserRandomId())){
            wrapper.like(H2AppUser::getUserRandomId,query.getUserRandomId());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getUserName())){
            wrapper.like(H2AppUser::getUserName,query.getUserName());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getInviteCode())){
            wrapper.eq(H2AppUser::getInvitationCode,query.getInviteCode());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getNickName())){
            wrapper.like(H2AppUser::getNickName,query.getNickName());
            exc=true;
        }
        if (query.getUserStatus()!=null){
            wrapper.eq(H2AppUser::getStatus,query.getUserStatus());
            exc=true;
        }
        if (query.getUserSysType()!=null){
            wrapper.eq(H2AppUser::getUserSysType,query.getUserSysType());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getEmail())){
            wrapper.like(H2AppUser::getEmail,query.getEmail());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getPhone())){
            wrapper.like(H2AppUser::getMobile,query.getPhone());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getPhone())){
            wrapper.like(H2AppUser::getMobile,query.getPhone());
            exc=true;
        }
        if (StringUtils.isNotBlank(query.getIp())){
            wrapper.eq(H2AppUser::getIp,query.getIp());
            exc=true;
        }
        if (query.getUserLevelId()!=null){
            wrapper.eq(H2AppUser::getUserLevel,query.getUserLevelId());
            exc=true;
        }
        if (!exc){
            //不执行查询
            return null;
        }
        List<H2AppUser> list=list(wrapper);
        if (CollectionUtils.isNotEmpty(list)){
            return list.stream().map(H2AppUser::getId).toList().stream().map(Long::valueOf).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public H2AppUser getbyUserName(String userName) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>()
                .eq(H2AppUser::getUserName, userName)
                .eq(H2AppUser::getDeleted,0);
        return baseMapper.selectOne(wrapper);
    }

    @Override
    public List<H2AppUser> getbyUserNameLike(String userName, Integer userType) {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(userName),H2AppUser::getUserName, userName);
        wrapper.eq(null != userType,H2AppUser::getUserType,userType);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public H2AppUser userSuperiorInfo(String inviteCode) {
        LambdaQueryWrapper<H2AppUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(H2AppUser::getInvitationCode, inviteCode);
        List<H2AppUser> appUsers = baseMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(appUsers) || appUsers.size() > 1) {
            throw new QysException(MessageUtils.message("invite.code.null"));
        }
        return appUsers.get(0);
    }

    @Override
    public List<H2AppUser> getYesterday() {
        return baseMapper.getYesterday();
    }

    @Override
    public Integer getbyLastLoginTime(SysHomeStatisticsDTO dto) {
        return baseMapper.getbyLastLoginTime(dto);
    }

    @Override
    public Integer getTodayPeopleNumber(Integer userSysType) {
        return baseMapper.getTodayPeopleNumber(userSysType);
    }

    @Override
    public List<UserChannelListVO> channelList() {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>();
        wrapper.eq(H2AppUser::getDeleted, 0);
        wrapper.eq(H2AppUser::getUserSysType, AppUserConstant.SysUserType.CHANNEL);
        List<H2AppUser> h2AppUsers=list(wrapper);
        List<UserChannelListVO> result= BeanUtil.copyToList(h2AppUsers,UserChannelListVO.class);
        return result;
    }

    @Override
    public void  addChannel(SysAppUserSaveDTO sysAppUserSaveDTO) {
        log.info("管理员添加渠道信息:{}", sysAppUserSaveDTO);

        //用户名重复校验
        H2AppUser appUser = getbyUserName(sysAppUserSaveDTO.getUserName());
        if(appUser != null){
            throw new QysException("duplicate user name");
        }

        H2AppUser user = new H2AppUser();
        BeanUtils.copyProperties(sysAppUserSaveDTO, user);
        user.setUpdateBy(SecurityUtils.getUsername());
        user.setUpdateTime(LocalDateTime.now());

        //新增
        if (StringUtils.isBlank(sysAppUserSaveDTO.getId())) {
            user.setUserSysType(AppUserConstant.SysUserType.CHANNEL);
            user.setStatus(0);
            user.setDeleted(false);
            user.setUserType(UserTypeEnum.REGULAR_USERS.getCode());
            user.setNickName(sysAppUserSaveDTO.getNickName());
            user.setCreateTime(LocalDateTime.now());
            user.setCreateBy(SecurityUtils.getUsername());

            //生成邀请码
            user.setInvitationCode(produceInviteCode());

            //用户显示Id（用户账号）
            user.setUserRandomId(getRandomId());

            //用户等级
            setUserLevel(user);
        }
        //生成密码信息
        generatePasswordAndSalt(sysAppUserSaveDTO.getPassword(), sysAppUserSaveDTO.getUserName(), user);

        saveOrUpdate(user);

        //用户余额
        financeUserAccountService.create(Long.valueOf(user.getId()));

        UserTeamEventDTO userTeamEventDTO=new UserTeamEventDTO();
        BeanUtil.copyProperties(user,userTeamEventDTO);
        applicationContext.publishEvent(new UserTeamEvent(userTeamEventDTO));
    }

    @Override
    public List<H2AppUser> userAll() {
        LambdaQueryWrapper<H2AppUser> wrapper = new LambdaQueryWrapper<H2AppUser>();
        wrapper.eq(H2AppUser::getDeleted, 0);
        wrapper.ne(H2AppUser::getUserSysType, AppUserConstant.SysUserType.CHANNEL);
        List<H2AppUser> h2AppUsers=list(wrapper);
        return h2AppUsers;
    }

    @Override
    public List<Long> getsubset(Long oldUserId) {
        return baseMapper.getsubset(oldUserId);
    }

    @Override
    public List<Long> getChildUserIds(List<Long> list) {
        return baseMapper.getChildUserIds(list);
    }

    @Override
    public List<String> gettreeList(String userId, Integer conditionType, Integer conditionCode) {
        List<H2AppUserTreeVo> list=baseMapper.gettreeList(userId);
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        //获取父节点
        List<H2AppUserTreeVo> collect = list.stream().filter(t -> t.getSuperior().toString().equals(userId)).map(
                m -> {
                    m.setStorey(1);
                    m.setChildren(getChildren(m, list));
                    return m;
                }
        ).collect(Collectors.toList());

        List<String> ids=new ArrayList<>();
        //1 用户直推 2 用户伞下 3 用户三代
        if (conditionType.intValue() == 1){
            ids=findChild(collect,userId,conditionType.intValue(),null);
        }else if (conditionType.intValue() == 2){
            ids=findChild(collect,userId,conditionType.intValue(),null);
        }else {
            ids=findChild(collect,userId,conditionType.intValue(),null);
        }
        if (null != conditionCode){
            // 1 真实用户 2 状态正常 3 充值用户
            if (conditionCode.intValue() == 1){
                List<String> finalIds = ids;
                ids=list.stream().filter(a-> finalIds.contains(a.getId()) && a.getUserSysType().intValue()==1).map(H2AppUserTreeVo::getId).collect(Collectors.toList());
            }else if (conditionCode.intValue() == 2){
                List<String> finalIds = ids;
                ids=list.stream().filter(a-> finalIds.contains(a.getId()) && a.getStatus()==0).map(H2AppUserTreeVo::getId).collect(Collectors.toList());
            }else {
                ids=h2AppUserRechargeWithdrawalsMapper.getUserRechargeList(ids);
            }
        }
        return ids;
    }

    @Override
    public List<String> gettreeList(String userId, Integer conditionCode) {
        List<H2AppUserTreeVo> list=baseMapper.gettreeList(userId);
        if (CollectionUtils.isEmpty(list)){
            return null;
        }
        List<String> ids = list.stream().map(H2AppUserTreeVo::getId).collect(Collectors.toList());
        if (null != conditionCode){
            // 1 真实用户 2 状态正常 3 充值用户
            if (conditionCode.intValue() == 1){
                ids=list.stream().filter(a->  a.getUserSysType().intValue()==1).map(H2AppUserTreeVo::getId).collect(Collectors.toList());
            }else if (conditionCode.intValue() == 2){
                ids=list.stream().filter(a->  a.getStatus()==0).map(H2AppUserTreeVo::getId).collect(Collectors.toList());
            }else  if (conditionCode.intValue() == 3){
                ids=h2AppUserRechargeWithdrawalsMapper.getUserRechargeList(ids);
            }
        }
        return ids;
    }

    @Override
    public List<TelephoneAreaCodeVO> getInternationalTelephoneAreaCode() {
        //判断语言
        Locale locale = LocaleContextHolder.getLocale();
        boolean en = locale.toLanguageTag().contains("en");
        return baseMapper.getInternationalTelephoneAreaCode(en ? "en" : "ch");
    }

    @Override
    public Integer getActivebyLastLoginTime(String ip) {
        return baseMapper.getActivebyLastLoginTime(ip);
    }

    @Override
    public List<H2AppUser> getActivebyLastLogin() {
        return baseMapper.getActivebyLastLogin();
    }

    @Override
    public Page<SysAppUserPageVo> foundationpage(SysAppUserQueryDTO userQueryDTO) {
        Page<SysAppUserPageVo> page = new Page<>(userQueryDTO.getPageNum(), userQueryDTO.getPageSize());
        List<SysAppUserPageVo> pageVoList = baseMapper.foundationpage(page, userQueryDTO);
        if (CollectionUtils.isNotEmpty(pageVoList)) {
            page.setRecords(pageVoList);
        }
        return page;
    }

    @Override
    public List<AppUserInfoTeamDetailVo> getbyUserids(Page<AppUserInfoTeamDetailVo> page,List<Long> list) {
        return baseMapper.getbyUserids(page,list);
    }

    /**
     * 调用递归
     */
    /**
     * 递归查询子节点
     * @param root  根节点
     * @param all   所有节点
     * @return 根节点信息
     */
    public static List<H2AppUserTreeVo> getChildren(H2AppUserTreeVo root, List<H2AppUserTreeVo> all) {
        List<H2AppUserTreeVo> children = all.stream().filter(t -> {
            return Objects.equals(t.getSuperior().toString(), root.getId());
        }).map(
                m -> {
                    m.setStorey(root.getStorey()+1);
                    m.setChildren(getChildren(m, all));
                    return m;
                }
        ).collect(Collectors.toList());
        return children;
    }
    //1 用户直推 2 用户伞下 3 用户三代
    public static  List<String> findChild(List<H2AppUserTreeVo> list,String userid,Integer conditionType,List<String> userids){
        for (H2AppUserTreeVo org:list){
            if(org.getSuperior().toString().equals(userid)){
                if (userids==null){
                    userids=new ArrayList<>();
                }
                if (org.getStorey().intValue() == 1 && conditionType.intValue() == 1){
                    userids.add(org.getId());
                }
                if (org.getStorey().intValue() <= 3 && conditionType.intValue() == 3){
                    userids.add(org.getId());
                }
                if (conditionType.intValue() == 2){
                    userids.add(org.getId());
                }
                findChild(list,org.getId(),conditionType,userids);   //递归实现
            }
        }
        return userids;
    }

    private Map<String,String> getUniqueID(String code) {

        Map<String, Object> map = Maps.newHashMap();
        try {
            map.put("code", URLDecoder.decode(code, "UTF-8"));
        } catch (Exception e) {
            throw new QysException("code decode fail");
        }
        map.put("client_id", clientId);
        map.put("client_secret", clientSecret);
        map.put("redirect_uri", redirectUri);
        map.put("grant_type", "authorization_code");
        String result = HttpUtil.post(tokenUrl, map);
        log.info("googleLogin result:{}",result);

        JSONObject jsonObject = JSONObject.parseObject(result);
        Object idToken = jsonObject.get("id_token");
        if(idToken == null){
            throw new QysException("code is error");
        }

        JWT user = JWT.of((String)idToken);
        String sub = (String) user.getPayload("sub");
        String email = (String) user.getPayload("email");

        HashMap<String, String> hashMap = Maps.newHashMap();
        hashMap.put("sub",sub);
        hashMap.put("email",email);
        return hashMap;

    }

    private String doLogin(HttpServletRequest request, H2AppUser appUser) {
        String ip=IpUtil.getIpAddr(request);
        LocalDateTime now=LocalDateTime.now();
        //用户最后一次登录
        baseMapper.updateUserLoginInfo(ip, now, Long.parseLong(appUser.getId()));

        //用户信息
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(Long.parseLong(appUser.getId()));
        loginUser.setUserName(appUser.getNickName());
        loginUser.setNickName(appUser.getNickName());
        loginUser.setUserSource((byte) 1);

        //检查是否导入用户到IM
        checkImImport(appUser);

        //设置token
        String token = IdUtils.fastUUID();
        //缓存token信息
        String tokenKey = CacheUtil.getKey(RedisConstant.USER_TOKEN, SysConstants.BEARER + token);
        redisCache.setCacheObject(tokenKey, loginUser);

        //根据用户Id设置用户token信息
        tokenKey = CacheUtil.getKey(RedisConstant.USER_ID_TOKEN, String.valueOf(loginUser.getUserId()));
        redisCache.setCacheObject(tokenKey, SysConstants.BEARER + token, 30L, TimeUnit.DAYS);

        LoginInfoDTO loginInfoDTO =new LoginInfoDTO();
        loginInfoDTO.setIp(ip);
        loginInfoDTO.setUserId(Long.parseLong(appUser.getId()));
        loginInfoDTO.setNow(now);
        applicationContext.publishEvent(new LoginEvent(loginInfoDTO));
        return token;
    }


    /**
     * 获取用户的指定用户
     * 1 用户直推 2 用户伞下 3 用户三代
     */
}
